package pl.edu.mimuw.irs.core.model.petrinet.workflow;

import java.util.Set;

import pl.edu.mimuw.irs.core.exception.InternalException;
import pl.edu.mimuw.irs.core.exception.InternalException.Cause;
import pl.edu.mimuw.irs.core.model.petrinet.Arc;
import pl.edu.mimuw.irs.core.model.petrinet.IPlace;
import pl.edu.mimuw.irs.core.model.petrinet.ITransition;
import pl.edu.mimuw.irs.core.model.petrinet.Net;

public class Workflow extends Net {

	private static final long serialVersionUID = -1400176297196385283L;
	
	// *** Attributes
	
	// Standard in-out places of workflow
	private IPlace in;
	private IPlace out;
	// Getters and setters
	public IPlace getIn() {
		if (this.in == null) {
			locateInOut();
		}
		return in;
	}
	public void setIn(IPlace in) {
		this.in = in;
	}
	public IPlace getOut() {
		if (this.out == null) {
			locateInOut();
		}
		return out;
	}
	public void setOut(IPlace out) {
		this.out = out;
	}
	
	// *** Methods

	public Workflow(Set<IPlace> places, Set<ITransition> transitions, Set<Arc> arcs) {
		super(places, transitions, arcs);
	}
	
	public Workflow() {
		super();
	}
	
	public void resetInOut() {
		setIn(null);
		setOut(null);
	}
	
	protected void locateInOut() {
		boolean foundIn = false;
		boolean foundOut = false;
		setIn(null);
		setOut(null);
		
		for (IPlace place : getPlaces()) {
			if (place.getIncomingArcs().size() == 0) {
				if (foundIn) throw new InternalException(Cause.WORKFLOW_TOO_MANY_IN_PLACES);
				setIn(place);
				foundIn = true;
			}
		}

		for (IPlace place : getPlaces()) {
			if (place.getOutgoingArcs().size() == 0) {
				if (foundOut) throw new InternalException(Cause.WORKFLOW_TOO_MANY_OUT_PLACES);
				setOut(place);
				foundOut = true;
			}
		}
		
		if (!foundIn) throw new InternalException(Cause.WORKFLOW_NO_IN_PLACE);
		if (!foundOut) throw new InternalException(Cause.WORKFLOW_OUT_PLACE);
	}

}
